﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace OCRTheNewHope
{
    public static class FileOperations
    {
        public static Random rnd = new Random();


        public static Digit[] ReadDatabase(string path, long skip = 0, int total = -1, int[] selectedDigits = null)
        {
            List<Digit> rVal = new List<Digit>();

            using (BinaryReader b = new BinaryReader(File.Open(path, FileMode.Open)))
            {
                int totalLength = b.ReadInt32();
                int width = b.ReadInt32();
                int height = b.ReadInt32();

                int length = total > 0 ? total : totalLength;

                b.BaseStream.Seek(skip * (width * height * 9 + 5), SeekOrigin.Current);
                int counter = (int)skip;

                while (counter < length && counter < totalLength)
                {
                    int digitID = b.ReadInt32();
                    byte digitValue = b.ReadByte();

                    if (selectedDigits != null && !selectedDigits.Contains(digitValue))
                    {
                        b.BaseStream.Seek(width * height * 9, SeekOrigin.Current);
                        counter++;
                        continue;
                    }

                    byte[,] original = new byte[height, width];
                    float[,] integral = new float[height, width];
                    float[,] integralRight = new float[height,width];

                    for (int i = 0; i < height; i++)
                        for (int j = 0; j < width; j++)
                            original[i, j] = b.ReadByte();

                    for (int i = 0; i < height; i++)
                        for (int j = 0; j < width; j++)
                            integral[i, j] = b.ReadSingle();

                    for (int i = 0; i < height; i++)
                        for (int j = 0; j < width; j++)
                            integralRight[i, j] = b.ReadSingle();


                    rVal.Add(new Digit(digitID, digitValue, original, integral,integralRight));
                 
                    counter++;
                }
            }

            return rVal.ToArray();
        }

        public static Digit[] ReadDatabaseOld(string path, long skip = 0, int total = -1, int[] selectedDigits = null)
        {
            List<Digit> rVal = new List<Digit>();

            using (BinaryReader b = new BinaryReader(File.Open(path, FileMode.Open)))
            {
                int totalLength = b.ReadInt32();
                int width = b.ReadInt32();
                int height = b.ReadInt32();

                int length = total > 0 ? total : totalLength;

                b.BaseStream.Seek(skip * (width * height * 9 + 5), SeekOrigin.Current);
                int counter = (int)skip;

                while (counter < length && counter < totalLength)
                {
                    int digitID = b.ReadInt32();
                    byte digitValue = b.ReadByte();

                    if (selectedDigits != null && !selectedDigits.Contains(digitValue))
                    {
                        b.BaseStream.Seek(width * height * 9, SeekOrigin.Current);
                        counter++;
                        continue;
                    }

                    byte[,] original = new byte[height, width];
                    float[,] integral = new float[height, width];

                    for (int i = 0; i < height; i++)
                        for (int j = 0; j < width; j++)
                            original[i, j] = b.ReadByte();

                    for (int i = 0; i < height; i++)
                        for (int j = 0; j < width; j++)
                            integral[i, j] = b.ReadSingle();

                    rVal.Add(new Digit(digitID, digitValue, original, integral));

                    counter++;
                }
            }

            return rVal.ToArray();
        }





        public static Digit[] ReadDatabaseRandomly(string path, int total = -1, int[] selectedDigits = null)
        {
            List<Digit> rVal = new List<Digit>();

            using (BinaryReader b = new BinaryReader(File.Open(path, FileMode.Open)))
            {
                int totalLength = b.ReadInt32();
                int width = b.ReadInt32();
                int height = b.ReadInt32();

                int length = total > 0 ? total : totalLength;

                int index = 0;

                while (index < length && index < totalLength)
                {
                    long randomNumber = FileOperations.rnd.Next(totalLength);
                    b.BaseStream.Seek(12 + randomNumber * (width * height * 9 + 5), SeekOrigin.Begin);
                    
                    int digitID = b.ReadInt32();
                    byte digitValue = b.ReadByte();

                    if (selectedDigits != null && !selectedDigits.Contains(digitValue))
                        continue;

                    byte[,] original = new byte[height, width];
                    float[,] integral = new float[height, width];

                    for (int i = 0; i < height; i++)
                        for (int j = 0; j < width; j++)
                            original[i, j] = b.ReadByte();

                    for (int i = 0; i < height; i++)
                        for (int j = 0; j < width; j++)
                            integral[i, j] = b.ReadSingle();

                    //rVal.Add(new Digit(digitID, digitValue, original, integral));

                    index++;
                }
            }

            return rVal.ToArray();
        }

        public static BinaryWriter CreateHeader(string path, int numItems, int numRows, int numCols)
        {
            BinaryWriter b = new BinaryWriter(File.Open(path, FileMode.Create));

            b.Write(numItems);
            b.Write(numRows);
            b.Write(numCols);

            return b;
        }

        public static void WriteDatabase(BinaryWriter b, Digit[] digits)
        {              
            for (int i = 0; i < digits.Length; i++)
            {
                b.Write(digits[i].DigitID);
                b.Write((byte)digits[i].DigitValue);

                for (int j = 0; j < digits[i].OriginalGrayscaleMatrix.GetLength(0); j++)
                    for (int k = 0; k < digits[i].OriginalGrayscaleMatrix.GetLength(1); k++)
                        b.Write((byte)digits[i].OriginalGrayscaleMatrix[j, k]);

                for (int j = 0; j < digits[i].IntegralMatrix.GetLength(0); j++)
                    for (int k = 0; k < digits[i].IntegralMatrix.GetLength(1); k++)
                        b.Write(digits[i].IntegralMatrix[j, k]);
            }
        }


        public static void WriteDoubleIntegralDatabase(BinaryWriter b, Digit[] digits)
        {
            for (int i = 0; i < digits.Length; i++)
            {
                b.Write(digits[i].DigitID);
                b.Write((byte)digits[i].DigitValue);

                for (int j = 0; j < digits[i].OriginalGrayscaleMatrix.GetLength(0); j++)
                    for (int k = 0; k < digits[i].OriginalGrayscaleMatrix.GetLength(1); k++)
                        b.Write((byte)digits[i].OriginalGrayscaleMatrix[j, k]);

                for (int j = 0; j < digits[i].IntegralMatrix.GetLength(0); j++)
                    for (int k = 0; k < digits[i].IntegralMatrix.GetLength(1); k++)
                        b.Write(digits[i].IntegralMatrix[j, k]);

                for (int j = 0; j < digits[i].IntegralMatrixRight.GetLength(0); j++)
                    for (int k = 0; k < digits[i].IntegralMatrixRight.GetLength(1); k++)
                        b.Write(digits[i].IntegralMatrixRight[j, k]);

            }
        }


        public static string GetLogPath()
        {
            int counter = 0;

            string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\";

            string rVal = "";
            do
            {
                rVal = desktopPath + "log" + counter.ToString("D3") + ".txt";
                counter++;
            }
            while (File.Exists(rVal));

            return rVal;
        }

        public static string GetImagePath()
        {
            int counter = 0;

            string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\";

            string rVal = "";
            do
            {
                rVal = desktopPath + "Images" + counter.ToString("D3");
                counter++;
            }
            while (Directory.Exists(rVal));

            return rVal;
        }
    }
}
